<?php  if (!defined('BASEPATH') || !defined('CRON')) exit('No direct script access allowed');

require_once APPPATH . 'controllers/cron.php';
require_once APPPATH . 'libraries/VideoEntry.php';
require_once APPPATH . 'libraries/TorrentEntry.php';

/**
 * Парсер видео
 *
 * @author Gennadiy Kozlenko
 */
class Cron_Parser extends Cron {
     
    /**
     * Страница
     *
     * @var int
     */
    var $_page = 1;
     
    /**
     * Конструктор класса
     *
     * @return Cron_Parser
     */
    function Cron_Parser() {
        parent::Cron();
        if (false !== $this->uri->segment(3)) {
            $this->_page = (int) $this->uri->segment(3);
            $this->log("Detect page " . $this->_page);
        }
        $this->load->config('parser');
        $this->load->helper('http');
        $this->load->helper('text');
        $this->load->helper('string');
        $this->load->model('m_video');
        $this->load->model('m_video_torrent');
        $this->load->model('m_torrent_screenshot');
    }
     
    /**
     * Метод по умолчанию
     *
     */
    function index() {
        $this->load->library('license');
        if (!$this->license->isActivated()) {
            $this->log('Application not activated yet.');
            exit;
        }
        $this->log('Start video parser');
        // Создаем объект парсинга дополнительной информации по видео
        $infoParsers = array();
        // Получаем список источников видео
        $sources = $this->getSources();
        if (0 < count($sources)) {
            $this->log('Found ' . count($sources) . ' active video sources');
            // Проходимся по каждому источнику видео
            foreach ($sources as $source) {
                // Подгружаем источник видео
                $file = APPPATH . 'libraries/TorrentParser/' . $source['name'] . '.php';
                if (file_exists($file)) {
                    $this->load->file($file);
                    try {
                        // Создаем объект парсера
                        $class = 'TorrentParser_' . $source['name'];
                        $parser = new $class();
                        // Устанавливаем страницу
                        $parser->setPage($this->_page);
                        // Получаем массив объектов видео
                        $entries = $parser->parseItems();
                        $this->sleep(1, 3);
                        if (0 < count($entries)) {
                            shuffle($entries);
                            $this->log('Found ' . count($entries) . ' torrent entries');
                            // Цикл по полученным объектам
                            foreach ($entries as $entry) {
                                $entry->setIdSource($source['id_source']);
                                if (0 == $this->torrentExists($entry)) {
                                    // Torrent с такой ссылкой еще не существует в базе данных
                                    $this->log('Parse url: ' . $entry->getLink());
                                    // Выпарсиваем детальную информацию по этому видео
                                    $entry = $parser->parseItem($entry);
                                    if (false !== $entry) {
                                        $videoParsed = false;
                                        // Проверяем на сушествование такого видео в базе
                                        if (0 < ($idVideo = $this->videoExists($entry->videoEntry))) {
                                            // Видео существует
                                            $entry->videoEntry->setIdVideo($idVideo);
                                            $videoParsed = true;
                                        } else {
                                            // Видео не существует, ищем...
                                            foreach ($infoParsers as $infoParser) {
                                                if (false !== ($videoEntry = $infoParser->parseItem($entry->videoEntry))) {
                                                    $entry->videoEntry = $videoEntry;
                                                    $videoParsed = true;
                                                    break;
                                                }
                                            }
                                            if ('' != $entry->videoEntry->getTitle()) {
                                                $videoParsed = true;
                                            }
                                        }
                                        if ($videoParsed) {
                                            if (0 < ($idVideo = $this->storeVideo($entry->videoEntry))) {
                                                if (0 < ($idTorrent = $this->storeTorrent($entry))) {
                                                    $this->log('Store torrent entry to database');
                                                } else {
                                                    // Ошибка при сохранении
                                                    $this->log('Cannot store torrent entry');
                                                }
                                            } else {
                                                // Ошибка при сохранении
                                                $this->log('Cannot store video entry');
                                            }
                                        } else {
                                            // Такое видео уже существует
                                            $this->log('Cannot parse additional information for video entry');
                                        }
                                    }
                                    $this->sleep(1, 3);
                                } else {
                                    // Такой торент уже существует
                                    $this->log('Torrent with this link already exists');
                                }
                            }
                        } else {
                            $this->log('No torrent entries found');
                        }
                    } catch (Exception $e) {
                        $this->log('Error: ' . $e->getMessage());
                    }
                } else {
                    $this->log('Error: Cannot found parser ' . $source['name']);
                }
            }
        }
        $this->log('Stop video parser');
    }
     
    /**
     * Получение массива источников видео
     *
     * @return array
     */
    function getSources() {
        $sources = array();
        $this->db->select('id_source, name')
            ->from('sources')
            ->where('status', 'active')
            ->order_by('position');
        $query = $this->db->get();
        if (0 < $query->num_rows()) {
            $sources = $query->result_array();
        }
        return $sources;
    }
     
    /**
     * Проверка на существование такого торрента в базе
     *
     * @param TorrentEntry $entry
     * @return int
     */
    function torrentExists(TorrentEntry $entry) {
        $idTorrent = 0;
        $this->db->select('id_torrent')
            ->from('video_torrents')
            ->where('linkhash', $entry->getLinkHash())
            ->limit(1);
        $query = $this->db->get();
        if (0 < $query->num_rows()) {
            $row = $query->row_array();
            $idTorrent = $row['id_torrent'];
        }
        return $idTorrent;
    }
     
    /**
     * Проверка на существование такого видео в базе
     *
     * @param VideoEntry $entry
     * @return int
     */
    function videoExists(VideoEntry $entry) {
        $idVideo = 0;
        $sql = "
      		SELECT
      			id_video
      		FROM
      			" . $this->db->dbprefix('videos') . "
      		WHERE
      			titlehash = ? AND
      			year BETWEEN ? AND ?
      		LIMIT
      			1
      	";
        $query = $this->db->query($sql, array($entry->getTitleHash(), $entry->getYear() - 1, $entry->getYear() + 1));
        if (0 < $query->num_rows()) {
            $row = $query->row_array();
            $idVideo = $row['id_video'];
        }
        return $idVideo;
    }
     
    /**
     * Сохранение изображения локально
     *
     * @param VideoEntry $entry
     * @return string
     */
    function storeImage($link) {
        $image = '';
        if ('' != $link) {
            $content = get_content($link, array(), $this->config->item('parser_timeout'));
            if (!empty($content) && false !== ($im = @imagecreatefromstring($content))) {
                $width = imagesx($im);
                $height = imagesy($im);
                imagedestroy($im);
                if ($width >= 100 && $height >= 100) {
                    // Получаем расширение файла
                    $ext = '.jpg';
                    $match = array();
                    $source = preg_replace('~\?.*$~', '', $link);
                    if (preg_match('~(\.[^\./]+)$~msi', $source, $match)) {
                        $ext = strtolower($match[1]);
                    }
                    if (!in_array($ext, array('.jpg', '.png', '.jpeg', '.jpe', '.gif'))) {
                        $ext = '.jpg';
                    }
                    $fileName = md5($link) . $ext;
                    $dirName = 'data/images/' . substr($fileName, 0, 2) . '/';
                    if (!file_exists(BASEPATH . '../' . $dirName)) {
                        mkdir(BASEPATH . '../' . $dirName);
                        @chmod(BASEPATH . '../' . $dirName, 0777);
                    }
                    if (false !== file_put_contents(BASEPATH . '../' . $dirName . $fileName, $content)) {
                        @chmod(BASEPATH . '../' . $dirName . $fileName, 0777);
                        $image = $dirName . $fileName;
                    }
                }
            }
        }
        return $image;
    }
     
    /**
     * Сохранение видео в базу
     *
     * @param VideoEntry $entry
     * @param array $source
     * @return int
     */
    function storeVideo(VideoEntry $entry) {
        $idVideo = $entry->getIdVideo();
        $result  = 0;
        if (0 < $idVideo || 0 < ($idVideo = $this->videoExists($entry))) {
            // Обновляем видео
            $entry->setIdVideo($idVideo);
            $result = $this->updateVideo($entry);
        } else {
            // Создаем новое видео
            $result = $this->createVideo($entry);
        }
        return $result;
    }
     
    /**
     * Создание нового видео
     *
     * @param VideoEntry $entry
     * @return int
     */
    function createVideo(VideoEntry $entry) {
        $idVideo = 0;
        $this->m_video->set_id(0);
        $this->m_video->set('title', $entry->getTitle());
        $this->m_video->set('orig_title', $entry->getOrigTitle());
        $this->m_video->set('titlehash', $entry->getTitleHash());
        $this->m_video->set('image', $this->storeImage($entry->getImage()));
        $this->m_video->set('year', (int) $entry->getYear());
        $this->m_video->set('length', $entry->getLength());
        $this->m_video->set('date_created', date('Y-m-d H:i:s'));
        $this->m_video->set('status', 'active');
        $this->m_video->set('is_featured', 'no');
        $this->m_video->set('description', $entry->getDescription());
        if ($this->m_video->update()) {
            $this->m_video->set_genres($this->getIdGenres($entry->getGenres()));
            $this->m_video->set_countries($this->getIdCountries($entry->getCountries()));
            $this->m_video->set_actors($this->getIdPersons($entry->getActors()));
            $this->m_video->set_directors($this->getIdPersons($entry->getDirectors()));
            $idVideo = $this->m_video->get_id('id_video');
            $entry->setIdVideo($idVideo);
        } else {
            print_r($this->errors->get_errors());
        }
        return $idVideo;
    }
     
    /**
     * Изменение видео
     *
     * @param VideoEntry $entry
     * @return int
     */
    function updateVideo(VideoEntry $entry) {
        $this->m_video->set_id($entry->getIdVideo());
        // Обновляем дату создания
        $this->m_video->set('date_created', date('Y-m-d H:i:s'));
        if ('' != $entry->getImage() && '' == $this->m_video->get('image')) {
            $this->m_video->set('image', $this->storeImage($entry->getImage()));
        }
        if (0 < $entry->getYear() && 0 == $this->m_video->get('year')) {
            $this->m_video->set('year', $entry->getYear());
        }
        if ('' != $entry->getLength() && '00:00:00' == $this->m_video->get('length')) {
            $this->m_video->set('length', $entry->getLength());
        }
        if ('' != $entry->getDescription() && '' == $this->m_video->get('description')) {
            $this->m_video->set('description', $entry->getDescription());
        }
        if (0 < count($entry->getGenres()) && 0 == count($this->m_video->get_genres())) {
            $this->m_video->set_genres($this->getIdGenres($entry->getGenres()));
        }
        if (0 < count($entry->getCountries()) && 0 == count($this->m_video->get_countries())) {
            $this->m_video->set_countries($this->getIdCountries($entry->getCountries()));
        }
        if (0 < count($entry->getDirectors()) && 0 == count($this->m_video->get_directors())) {
            $this->m_video->set_directors($this->getIdPersons($entry->getDirectors()));
        }
        if (0 < count($entry->getActors()) && 0 == count($this->m_video->get_actors())) {
            $this->m_video->set_directors($this->getIdPersons($entry->getDirectors()));
        }
        $this->m_video->update();
        return $entry->getIdVideo();
    }
     
    /**
     * Update screenshots
     * @param VideoEntry $entry
     */
    function updateScreenshots(TorrentEntry $entry) {
        foreach ($entry->getScreenshots() as $screenshot) {
            $linkhash = md5($screenshot['link']);
            $count = $this->db->from('torrent_screenshots')
                ->where('id_torrent', $entry->getIdTorrent())
                ->where('linkhash', $linkhash)
                ->count_all_results();
            if (0 == $count) {
                $image = $this->storeImage($screenshot['image']);
                if (!empty($image)) {
                    $this->m_torrent_screenshot->set_id(0);
                    $this->m_torrent_screenshot->set('id_torrent', $entry->getIdTorrent());
                    $this->m_torrent_screenshot->set('link', $screenshot['link']);
                    $this->m_torrent_screenshot->set('linkhash', $linkhash);
                    $this->m_torrent_screenshot->set('image', $image);
                    if (!$this->m_torrent_screenshot->update()) {
                        print_r($this->errors->get_errors());
                    } else {
                    }
                }
            }
        }
    }
     
    /**
     * Store torrent entry
     * @param TorrentEntry $entry
     * @return int
     */
    function storeTorrent(TorrentEntry $entry) {
        $idTorrent = 0;
        $this->m_video_torrent->set_id((int) $entry->getIdTorrent());
        $this->m_video_torrent->set('id_video', $entry->videoEntry->getIdVideo());
        $this->m_video_torrent->set('id_source', $entry->getIdSource());
        $this->m_video_torrent->set('link', $entry->getLink());
        $this->m_video_torrent->set('linkhash', $entry->getLinkHash());
        $this->m_video_torrent->set('torrent', $entry->getTorrent());
        $this->m_video_torrent->set('title', mb_substr($entry->getTitle(), 0, 200, 'utf-8'));
        $this->m_video_torrent->set('size', $entry->getSize());
        $this->m_video_torrent->set('format', mb_substr($entry->getFormat(), 0, 50, 'utf-8'));
        $this->m_video_torrent->set('video_codec', mb_substr($entry->getVideoCodec(), 0, 50, 'utf-8'));
        $this->m_video_torrent->set('audio_codec', mb_substr($entry->getAudioCodec(), 0, 50, 'utf-8'));
        $this->m_video_torrent->set('translate', mb_substr($entry->getTranslate(), 0, 200, 'utf-8'));
        $this->m_video_torrent->set('quality', mb_substr($entry->getQuality(), 0, 200, 'utf-8'));
        $this->m_video_torrent->set('video', $entry->getVideo());
        $this->m_video_torrent->set('audio', $entry->getAudio());
        if ($this->m_video_torrent->update()) {
            $idTorrent = $this->m_video_torrent->get_id('id_torrent');
            $entry->setIdTorrent($idTorrent);
            $this->updateScreenshots($entry);
        } else {
            print_r($this->errors->get_errors());
        }
        return $idTorrent;
    }
     
    /**
     * Получение идентификаторов жанров
     *
     * @param array $genres
     * @return array
     */
    function getIdGenres($genres) {
        $ids = array();
        foreach ($genres as $genre) {
            $genre = trim($genre, ';.');
            $genre = rucfirst($genre);
            $slug = url_title(transliteration($genre), 'dash', true);
            $this->db->select('id_genre')
                ->from('genres')
                ->where('title', $genre)
                ->or_where('slug', $slug)
                ->limit(1);
            $query = $this->db->get();
            if (0 < $query->num_rows()) {
                $row = $query->row_array();
                array_push($ids, $row['id_genre']);
            }
        }
        return $ids;
    }
     
    /**
     * Получение идентификаторов стран
     *
     * @param array $countries
     * @return array
     */
    function getIdCountries($countries) {
        $ids = array();
        foreach ($countries as $country) {
            $country = trim($country, ';.');
            $slug = url_title(transliteration($country), 'dash', true);
            $this->db->select('id_country')
                ->from('countries')
                ->where('title', $country)
                ->or_where('slug', $slug)
                ->limit(1);
            $query = $this->db->get();
            if (0 < $query->num_rows()) {
                $row = $query->row_array();
                array_push($ids, $row['id_country']);
            }
        }
        return $ids;
    }
     
    /**
     * Получение идентификаторов персон
     *
     * @param array $persons
     * @return array
     */
    function getIdPersons($persons) {
        $ids = array();
        foreach ($persons as $person) {
            $person = trim(html_entity_decode($person), ';.');
            $length = mb_strlen($person, 'utf-8');
            if ($length > 60 || $length < 5) {
                continue;
            }
            $slug = url_title(transliteration($person), 'dash', true);
            $this->db->select('id_person')
                ->from('persons')
                ->where('title', $person)
                ->or_where('slug', $slug)
                ->limit(1);
            $query = $this->db->get();
            if (0 < $query->num_rows()) {
                $row = $query->row_array();
                array_push($ids, $row['id_person']);
            } else {
                $db_data = array(
               		'title' => $person,
               		'slug'  => $slug
                );
                $this->db->insert('persons', $db_data);
                array_push($ids, $this->db->insert_id());
            }
        }
        return $ids;
    }
     
}
